package com.cqupt.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cqupt.mapper.BusinessMapper;
import com.cqupt.mapper.BusinessMapper;
import com.cqupt.pojo.Business;
import com.cqupt.pojo.Databases;
import com.cqupt.service.BusinessService;
import com.cqupt.service.ItemService;
import com.cqupt.utils.APIUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class BusinessServiceImpl implements BusinessService {

    @Autowired
    private BusinessMapper businessMapper;

    @Autowired
    private ItemService itemService;

    /**
     * 通过hostid，key获得item信息
     * @param hostid 主机的id
     * @param key 键值
     * @return 返回单个 item 的信息
     */
    @Override
    public List<Map<String, Object>> getItemInfo(String hostid, String key) {
        // 获得token令牌
        final String token = APIUtils.getToken();
        // 封装输出参数
        List<String> output = new ArrayList<>();
        output.add("name");
        output.add("error");
        output.add("lastvalue");
        // 封装接口参数
        Map<String, Object> paramsMap = new HashMap<String, Object>() {{
            put("jsonrpc", "2.0");
            put("method", "item.get");
            put("id", 1);
            put("auth", token);
            put("params", new HashMap<String, Object>() {{
                put("output", output);
                put("hostids", hostid);
                put("search", new HashMap<String, Object>() {{
                    put("key_", key);
                }});
            }});
        }};
        // 结果序列化
        Map<String, Object> responseMap = APIUtils.sendRequest(JSON.toJSONString(paramsMap, SerializerFeature.WriteMapNullValue));
        List<Map<String, Object>> resultList = (List<Map<String, Object>>) responseMap.get("result");
        // 返回结果
        return resultList;
    }

    /**
     * 判断MySQL 状态 Up(1) or Down(0)
     * @param hostid 传入主机的id
     * @return 返回对应的数据库是否开启
     */
    @Override
    public Integer getMysqlStatus(String hostid) {
        //  定义键值
        String key = "mysql.ping[\"{$MYSQL.HOST}\",\"{$MYSQL.PORT}\"]";
        // 通过键值和主机id获得监控项信息
        List<Map<String, Object>> result = getItemInfo(hostid, key);
        // 获得监控项信息 0为down 1为up
        String lastvalue = result.get(0).get("lastvalue").toString();
//        String error = result.get(0).get("error").toString();
        if ("0".equals(lastvalue))
            return 0;
        return 1;
    }

    /**
     * 获取所有的 业务，不包括包含的设备
     * @return 返回所有的业务
     */
    @Override
    public List<Map<String, Object>> getAllBusiness() {
        List<Map<String, Object>> business = businessMapper.getAllBusiness();
        // 便于前端树形展开，添加 hasChildren 属性
        for (Map<String, Object> map : business) {
            map.put("hasChildren", true);
        }
        return business;
    }

    /**
     * 通过业务的 id 获取属于此业务的主机
     * @param params 传入业务的id
     * @return 返回属于此业务的所有主机
     */
    @Override
    public List<Map<String, Object>> getBusinessInfoDeviceById(Map<String, Object> params) {
        Integer id = (Integer) params.get("id");
        List<Map<String, Object>> device = businessMapper.getBusinessInfoDeviceById(params);
        // 为了方便前端 tree 控件，报重复key错误
        for (Map<String, Object> map : device) {
            // 主机的真实 id
            map.put("real_id", map.get("id"));
            // 为了绑定，业务id_主机id
            map.put("id", id + "_" + map.get("id"));
        }
        return businessMapper.getBusinessInfoDeviceById(params);
    }

    /**
     * 通过业务的 id 获取属于此业务的数据库
     * @param params 传入业务的id
     * @return 返回属于此业务的所有数据库
     */
    @Override
    public List<Map<String, Object>> getBusinessInfoDatabaseById(Map<String, Object> params) {
        Integer id = (Integer) params.get("id");
        List<Map<String, Object>> database = businessMapper.getBusinessInfoDatabaseById(params);
        // 为了方式前端 tree 控件，报重复key错误。处理同上
        for (Map<String, Object> map : database) {
            map.put("real_id", map.get("id"));
            map.put("id", id + "_" + map.get("id"));
        }
        return businessMapper.getBusinessInfoDatabaseById(params);
    }

    /**
     * 通过业务的 id 得到属于此业务的 设备、数据库
     * @param params 传入业务的id
     * @return 返回属于此业务的所有设备、数据库
     */
    @Override
    public List<Map<String, Object>> getBusinessInfoById(Map<String, Object> params) {
        List<Map<String, Object>> device = getBusinessInfoDeviceById(params);
        // 为了区分结果，调用不同的接口后，传入 type 属性，为了前端展示和区分
        for (Map<String, Object> map : device) {
            map.put("type", "设备");
        }
        List<Map<String, Object>> database = getBusinessInfoDatabaseById(params);
        for (Map<String, Object> map : database) {
            map.put("type", "数据库");
        }
        List<Map<String, Object>> result = new ArrayList<>();
        result.addAll(device);
        result.addAll(database);
        return result;
    }

    /**
     * 获取所有的设备
     * @return 所有的设备（主机）
     */
    @Override
    public List<Map<String, Object>> getAllHosts() {
        List<Map<String, Object>> hosts = businessMapper.getAllHosts();
        List<Map<String, Object>> res = new ArrayList<>();
        // 前端用了懒加载，为了展示数据
        Map<String, Object> temp = new HashMap<String, Object>() {{
            put("id", 0);
            put("real_id", 0);
            put("name", "设备名称");
            put("children", hosts);
        }};
        res.add(temp);
        return res;
    }

    /**
     * 根据主机的id获取主机的名称
     * @param ids 主机的id列表
     * @return 返回ids对应的所有主机名称
     */
    @Override
    public List<String> getHostNameByIds(List<Integer> ids) {
        return businessMapper.getHostNameByIds(ids);
    }

    /**
     * 根据数据库的id获取数据库的名称
     * @param ids 主机的id列表
     * @return 返回id对应的所有数据库名称
     */
    @Override
    public List<String> getDatabaseNameByIds(List<Integer> ids) {
        return businessMapper.getDatabaseNameByIds(ids);
    }

    /**
     * 获取所有的数据库
     * @return 所有的数据库
     */
    @Override
    public List<Map<String, Object>> getAllDatabases() {
        List<Map<String, Object>> databases = businessMapper.getAllDatabases();
        List<Map<String, Object>> res = new ArrayList<>();
        Map<String, Object> temp = new HashMap<String, Object>() {{
            put("id", 0);
            put("real_id", 0);
            put("name", "数据库名");
            put("children", databases);
        }};
        res.add(temp);
        return res;
    }

    /**
     * 获得全部主机（用于数据库管理查询）
     * @param pageSize 分页大小
     * @param currentPage 当前页
     * @return 当前页的所有主机
     */
    @Override
    public List<Map<String, Object>> getAllDatabasesReal(String pageSize, String currentPage) {
        Integer pageSizeInt = Integer.valueOf(pageSize);
        Integer currentPageInt = Integer.valueOf(currentPage);
        // 分页查询定义start & end
        int start = (currentPageInt - 1) * pageSizeInt;
        int end = pageSizeInt;
        // 获取所有数据库
        List<Map<String, Object>> resultList = businessMapper.getAllDatabasesReal(start, end);
        String key = "";
        for (int i = 0; i < resultList.size(); i++) {
            String hostid = resultList.get(i).get("hostid").toString();
            String lastvalue = "0";
            switch (resultList.get(i).get("databasestype").toString()){
                case "mysql":
                    key = "mysql.ping";
                    break;
                case "oracle":
                    key = "oracle.ping";
                    break;
                case "sql server":
                    key = "sqlserver.ping";
                    break;
                case "达梦":
                    key = "dm.ping";
                    break;
                default:
                    break;
            }
            int status = getStatusByHostid(hostid);
            if (0 == status)
                lastvalue = "0";
            else {
                // 通过键值和主机id获得监控项id
                List<Map<String, Object>> result = getItemInfo(hostid, key);
                // 1为up 0为down
                if (result.size() == 1) {
                    lastvalue = result.get(0).get("lastvalue").toString();
                }
            }
            // 将查询到的信息重新更新到数据库中
//            System.out.println(lastvalue);
            businessMapper.modifyDatabasesStatus(resultList.get(i).get("databasesid").toString(), lastvalue);
            resultList.get(i).put("databasesstatus", lastvalue);
//            System.out.println(resultList.get(i));
        }
        return resultList;
    }

    /**
     * 获得全部主机数量
     * @return 全部主机数量
     */
    @Override
    public Integer getAllDatabasesCount() {
        return Integer.valueOf(businessMapper.getAllDatabasesCounts().get(0).get("total").toString());
    }

    /**
     * 添加数据库
     * @param params 传入新增数据库的所有信息
     * @return 返回添加数据看是否成功
     */
    @Override
    public Integer addDatabases(Map<String, Object> params) {
        // 主机id
        String hostid = params.get("hostid").toString();
//        String username = params.get("username").toString();
//        String password = params.get("password").toString();
        // 数据库端口号
        String databasesport = "";
        // 数据库描述
        String databasesdescription = params.get("databasesdescription").toString();
        // 数据库状态
        String databasesstatus = "0";
        // 数据库名字
        String databasesname = params.get("databasesname").toString();
        // 数据库所属ip
        String databasesip = getIPbyHostid(hostid);
        // 数据库类型
        String databasestype = params.get("databasestype").toString();
        // 键值
        String key = "";
        // 添加数据库时添加监控项，监控项参数 allNewsForItem
        Map<String, Object> allNewsForItem = null;
        switch (databasestype){
            case "1":
                databasestype = "mysql";
                databasesport = "3306";
                key = "mysql.ping";
                allNewsForItem = new HashMap<String,Object>(){{
                    put("delay","1m");
                    put("hostid",hostid);
                    // 通过hostid获得主机组id
                    put("interfaceid",itemService.getInterfaceidBuHostid(hostid));
                    put("key_","mysql.ping");
                    put("name","mysql status");
                    put("type",0);
                    put("value_type",0);
                    put("description","");
                    put("history","90d");
                    put("trends","365d");
                }};
                break;
            case "2":
                databasestype = "oracle";
                databasesport = "1521";
                key = "oracle.ping";
                allNewsForItem = new HashMap<String,Object>(){{
                    put("delay","1m");
                    put("hostid",hostid);
                    // 通过hostid获得主机组id
                    put("interfaceid",itemService.getInterfaceidBuHostid(hostid));
                    put("key_","oracle.ping");
                    put("name","oracle status");
                    put("type",0);
                    put("value_type",0);
                    put("description","");
                    put("history","90d");
                    put("trends","365d");
                }};
                break;
            case "3":
                databasestype = "sql server";
                databasesport = "1433";
                key = "sqlserver.ping";
                allNewsForItem = new HashMap<String,Object>(){{
                    put("delay","1m");
                    put("hostid",hostid);
                    // 通过hostid获得主机组id
                    put("interfaceid",itemService.getInterfaceidBuHostid(hostid));
                    put("key_","sqlserver.ping");
                    put("name","sqlserver status");
                    put("type",0);
                    put("value_type",0);
                    put("description","");
                    put("history","90d");
                    put("trends","365d");
                }};
                break;
            case "4":
                databasestype = "达梦";
                databasesport = "5236";
                key = "dm.ping";
                allNewsForItem = new HashMap<String,Object>(){{
                    put("delay","1m");
                    put("hostid",hostid);
                    // 通过hostid获得主机组id
                    put("interfaceid",itemService.getInterfaceidBuHostid(hostid));
                    put("key_","dm.ping");
                    put("name","dm status");
                    put("type",0);
                    put("value_type",0);
                    put("description","");
                    put("history","90d");
                    put("trends","365d");
                }};
                break;
            default:
                databasestype = "其他";
                key = "";
                break;
        }
        List<Map<String, Object>> result = getItemInfo(hostid, key);
        if (result.size() == 1) {
            databasesstatus = result.get(0).get("lastvalue").toString();
        }
        // 判断同IP下的数据库是否存在，若存在结果为1，返回0！
        String num = businessMapper.isExist(databasesip,databasestype).get("num").toString();
        if ("1".equals(num))
            return 0;
        // 如果查询结果为0，即未在数据库中查询到该信息，返回1！
        Map<String,Object> items = itemService.creatMonitorItem(allNewsForItem,0);
        String flag = items.get("flag").toString();
        String itemsid = items.get("message").toString();
        Databases databases = new Databases(databasesname, databasesip, databasestype, hostid, databasesport, databasesdescription,databasesstatus,itemsid);
        return businessMapper.addDatabases(databases);
    }

    /**
     * 修改数据库
     * @param params 需要被修改的数据库的id、及要改的新值
     * @return 返回是否修改成功
     */
    @Override
    public Integer modifyDatabases(Map<String, Object> params) {
        Integer databasesid = Integer.valueOf(params.get("databasesid").toString()); // 数据库id
        String databasesname = params.get("databasesname").toString(); // 数据库名称
        String databasesip = params.get("databasesip").toString(); //数据库所属ip
        String databasestype = params.get("databasestype").toString(); // 数据库类型
        String hostid = params.get("hostid").toString(); // 主机id
        String databasesport = params.get("databasesport").toString(); // 数据库端口号
        String databasesdescription = params.get("databasesdescription").toString(); //数据库描述
        // 封装数据库实体类 Databases
        switch (databasestype){
            case "1":
                databasestype="mysql";
                break;
            case "2":
                databasestype="oracle";
                break;
            case "3":
                databasestype = "sql server";
                break;
            case "4":
                databasestype="达梦";
        }
        Databases databases = new Databases(databasesid, databasesname, databasesip, databasestype, hostid, databasesport, databasesdescription);
        // 调用mapper修改数据库
        return businessMapper.modifyDatabases(databases);
    }

    /**
     * 删除数据库
     * @param databasesid 传入数据库的id
     * @return 返回是否删除成功
     */
    @Override
    public Integer delDatabases(String databasesid) {
        Map<String,Object> map = businessMapper.getADatabases(databasesid);
        String itemsid = map.get("itemsid").toString();
        ArrayList itemsList = new ArrayList();
        itemsList.add(itemsid);
        itemService.deleteMonitorItem(itemsList);
        return businessMapper.delDatabases(databasesid);
    }

    /**
     * 获得一个数据库信息、用于修改
     * @param databasesid 传入数据库的id
     * @return 返回对应的数据库的所有信息
     */
    @Override
    public Map<String, Object> getADatabases(String databasesid) {
        return businessMapper.getADatabases(databasesid);
    }

    /**
     * 删除业务（通过id）
     * @param params 其中有需被删除的业务id
     * @return 返回是否删除成功
     */
    @Override
    public Integer deleteBusinessById(Map<String, Object> params) {
        return businessMapper.deleteBusinessById(params);
    }

    @Override
    public String getBusinessNameById(Integer business_id) {
        return businessMapper.getBusinessNameById(business_id);
    }

    /**
     * 取消业务和主机的关联（删除业务与主机的关联关系）
     * @param params params 中有业务的id、主机的id等
     * @return 返回是否删除成功
     */
    @Override
    public Integer cancelBusinessAndHostRelation(Map<String, Object> params) {
        return businessMapper.cancelBusinessAndHostRelation(params);
    }

    /**
     * 取消业务和数据库的关联（删除业务与数据库的关联关系）
     * @param params params 中有业务的id、数据库的id等
     * @return 返回是否删除成功
     */
    @Override
    public Integer cancelBusinessAndDatabasesRelation(Map<String, Object> params) {
        return businessMapper.cancelBusinessAndDatabasesRelation(params);
    }

    /**
     * 添加业务，其中调用了添加业务和主机、数据的关机接口
     * @param params 在数据库中新增业务
     * @return 返回是否新增成功
     */
    @Override
    public Integer addBusiness(Map<String, Object> params) {
        String name = (String) params.get("name");
        List<Integer> hosts = (List<Integer>) params.get("hosts");
        List<Integer> databases = (List<Integer>) params.get("databases");
        Business business = new Business(name);
        businessMapper.addBusiness(business);
        Integer id = business.getBusiness_id();
        List<Map<String, Object>> info1 = new ArrayList<>();
        // 此处为了方便 添加业务和主机关系 操作，区分业务id 和 主机id
        for (Integer integer : hosts) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", id);
            temp.put("hostId", integer);
            info1.add(temp);
        }
        System.out.println(info1);
        Integer i = businessMapper.addBusinessAndHostRelation(info1);
        // 如果没有传入数据库，直接返回。否则继续为业务添加数据库
        if (databases.size() == 0)
            return i;
        // 此处同理，区分业务id 和 数据库id
        List<Map<String, Object>> info2 = new ArrayList<>();
        for (Integer integer : databases) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", id);
            temp.put("databaseId", integer);
            info2.add(temp);
        }
        System.out.println(info2);
        return businessMapper.addBusinessAndDatabaseRelation(info2);
    }

    /**
     * 添加业务 和主机的关系（将主机与业务关联）
     * @param params 其中有业务的id、主机的id等参数
     * @return 是否操作成功
     */
    @Override
    public Integer addBusinessAndHostRelation(Map<String, Object> params) {
        List<Map<String, Object>> info = new ArrayList<>();
        Integer id = (Integer) params.get("id");
        List<Integer> list = (List<Integer>) params.get("hostList");
        // 方便前端展示，区分业务id 和 主机id
        for (Integer integer : list) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", id);
            temp.put("hostId", integer);
            info.add(temp);
        }
        return businessMapper.addBusinessAndHostRelation(info);
    }

    /**
     * 添加业务 和数据库的关系（将数据库与业务关联）
     * @param params 其中有业务的id、数据库的id等参数
     * @return 是否操作成功
     */
    @Override
    public Integer addBusinessAndDatabaseRelation(Map<String, Object> params) {
        List<Map<String, Object>> info = new ArrayList<>();
        Integer id = (Integer) params.get("id");
        List<Integer> list = (List<Integer>) params.get("databaseList");
        // 同样，为了前端展示，区分不同的 id
        for (Integer integer : list) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", id);
            temp.put("databaseId", integer);
            info.add(temp);
        }
        return businessMapper.addBusinessAndDatabaseRelation(info);
    }

    /**
     * 根据主机id获取业务
     * @param hostId 传入主机的id值
     * @return 返回与主机id关联的所有业务
     */
    @Override
    public List<Map<String, Object>> getBusinessByHostId(String hostId) {
        return businessMapper.getBusinessByHostId(hostId);
    }

    /**
     * 根据数据库id获取业务
     * @param databaseId 传入数据库的 id逐渐
     * @return 返回与数据库id关联的所有业务
     */
    @Override
    public List<Map<String, Object>> getBusinessByDatabaseId(String databaseId) {
        return businessMapper.getBusinessByDatabaseId(databaseId);
    }

    /**
     * 通过hostid获得主机ip
     * @param hostid 传入主机的 id
     * @return 返回主机对应的 ip 地址
     */
    @Override
    public String getIPbyHostid(String hostid) {
        // 获得token令牌
        final String token = APIUtils.getToken();
        ArrayList<String> temp = new ArrayList<>();
        // 封装输出参数
        temp.add("interfaceid");
        temp.add("ip");
        // 查询参数
        Map<String, Object> paramsMap = new HashMap<String, Object>(){{
            put("jsonrpc", "2.0");
            put("method", "host.get");
            put("id", 1);
            put("auth", token);
            put("params", new HashMap<String, Object>(){{
                put("output", "hostid");
                put("hostids",hostid);
                put("selectInterfaces",temp);
            }});
        }};
        // 结果序列化
        Map<String, Object> responseMap = APIUtils.sendRequest(JSON.toJSONString(paramsMap, SerializerFeature.WriteMapNullValue));
        // 将结果转化为JSONArray
        JSONArray arr = (JSONArray) responseMap.get("result");
        JSONObject obj = arr.getJSONObject(0);
        JSONArray arrfinal = (JSONArray) obj.get("interfaces");
        // 将结果转化为JSONObject
        JSONObject jobj = arrfinal.getJSONObject(0);
        // 只返回ip （String类型）
        return jobj.get("ip").toString();
    }

    /**
     * 获得业务资源报表统计报表数据
     * @return 业务资源报表统计报表数据
     */
    @Override
    public List<Map<String, Object>> getBusinessReport() {
        return businessMapper.getBusinessReport();
    }

    /**
     * 获得业务下数据库信息
     * @param business_fk 传入业务的外键
     * @return 返回也业务相关的主机信息
     */
    @Override
    public List<Map<String, Object>> getDatabasesBussinessInfo(String business_fk) {
        return businessMapper.getDatabasesBussinessInfo(business_fk);
    }

    /**
     * 获得业务下主机信息
     * @param business_fk 传入业务的外键
     * @return 返回与业务相关的主机信息
     */
    @Override
    public List<Map<String, Object>> getHostsBussinessInfo(String business_fk) {
        return businessMapper.getHostsBussinessInfo(business_fk);
    }

    /**
     * 通过主机id获得判断主机的可用性
     * @param hostid 传入主机ID
     * @return 返回对应主机的状态
     */
    @Override
    public Integer getStatusByHostid(String hostid) {
        final String token = APIUtils.getToken();
        final String[] outputs = {"available","snmp_available", "ipmi_available", "jmx_available"};
        // 传入查询参数
        Map<String, Object> paramsMap = new HashMap<String, Object>(){{
            put("jsonrpc", "2.0");
            put("method", "host.get");
            put("id", 1);
            put("auth", token);
            put("params", new HashMap<String, Object>(){{
                put("hostids",hostid);
                put("output", outputs);
            }});
        }};
        Map<String, Object> responseMap = APIUtils.sendRequest(JSON.toJSONString(paramsMap, SerializerFeature.WriteMapNullValue));
        List<Map<String,String>> result =  (List<Map<String,String>>)responseMap.get("result");
        // 判断结果是否为空
        if (result.size()==0)
            return 0;
        else{
            String available = result.get(0).get("available");
            String snmp_available = result.get(0).get("snmp_available");
            String jmx_available = result.get(0).get("jmx_available");
            String ipmi_available = result.get(0).get("ipmi_available");
            if ("1".equals(available) || "1".equals(snmp_available) || "1".equals(jmx_available) || "1".equals(ipmi_available))
                return 1;
            return 0;
        }
    }
}
